package com.jkdz.spyke.flexUI.helpers {
	
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import mx.events.MoveEvent;
	import mx.events.ResizeEvent;
	
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class Reflector extends UIComponent {
		
		private var _target : UIComponent;
		private var _alphaGradientBitmap : BitmapData;
		private var _targetBitmap : BitmapData;
		private var _resultBitmap : BitmapData;
		
		private var _falloff : Number = 0.5;
		
		[Bindable]
		public function get target() : UIComponent {
			return _target;
		}
		
		public function set target(value : UIComponent) : void {
			if (_target != null) {
				_target.removeEventListener(FlexEvent.UPDATE_COMPLETE, handleTargetUpdate, true);
				_target.removeEventListener(MoveEvent.MOVE, handleTargetMove);
				_target.removeEventListener(ResizeEvent.RESIZE, handleTargetResize);
				
				clearCachedBitmaps();
			}
			
			_target = value;
			
			if (_target != null) {
				_target.addEventListener(FlexEvent.UPDATE_COMPLETE, handleTargetUpdate, true);
				
				_target.addEventListener(MoveEvent.MOVE, handleTargetMove);
				_target.addEventListener(ResizeEvent.RESIZE, handleTargetResize);
				
				invalidateDisplayList();
			}
		}
		
		[Bindable]
		public function get falloff() : Number {
			return _falloff;
		}
		
		public function set falloff(value : Number) : void {
			_falloff = value;
			_alphaGradientBitmap = null;
			
			invalidateDisplayList();
		}
		
		private function handleTargetUpdate(event : FlexEvent) : void {
			invalidateDisplayList();
		}
		
		private function handleTargetMove(event : MoveEvent) : void {
			move(_target.x, _target.y + _target.height);
		}
		
		private function handleTargetResize(event : ResizeEvent) : void {
			clearCachedBitmaps();
			width = _target.width;
			height = _target.height;
			invalidateDisplayList();
		}
		
		override protected function updateDisplayList(unscaledWidth : Number, unscaledHeight : Number) : void {
			if (_target != null) {
				createBitmaps(_target);
				
				var rect : Rectangle = new Rectangle(0, 0, _target.width, _target.height);
				
				_targetBitmap.fillRect(rect, 0x00000000);
				_targetBitmap.draw(_target, new Matrix());
				
				_resultBitmap.fillRect(rect, 0x00000000);
				_resultBitmap.copyPixels(_targetBitmap, rect, new Point(), _alphaGradientBitmap);
				
				var transform : Matrix = new Matrix();
				transform.scale(1, -1);
				transform.translate(0, _target.height);
				
				graphics.clear();
				graphics.beginBitmapFill(_resultBitmap, transform, false);
				graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
			}
		}
		
		private function clearCachedBitmaps() : void {
			_alphaGradientBitmap = null;
			_targetBitmap = null;
			_resultBitmap = null;
		}
		
		private function createBitmaps(target : UIComponent) : void {
			if (_alphaGradientBitmap == null) {
				_alphaGradientBitmap = new BitmapData(target.width, target.height, true, 0x00000000);
				var gradientMatrix : Matrix = new Matrix();
				var gradientSprite : Sprite = new Sprite();
				gradientMatrix.createGradientBox(target.width, target.height * _falloff, Math.PI / 2, 0, target.height * (1.0 - _falloff));
				gradientSprite.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF], [0, 0.7], [0, 255], gradientMatrix);
				gradientSprite.graphics.drawRect(0, target.height * (1.0 - _falloff), target.width, target.height * _falloff);
				gradientSprite.graphics.endFill();
				_alphaGradientBitmap.draw(gradientSprite, new Matrix());
			}
			if (_targetBitmap == null) {
				_targetBitmap = new BitmapData(target.width, target.height, true, 0x00000000);
			}
			if (_resultBitmap == null) {
				_resultBitmap = new BitmapData(target.width, target.height, true, 0x00000000);
			}
		}
	}
}
